<?php
	
	namespace Aspic\Controller;
	use Aspic as A;
	
	/**
	* Contains methods that are shared both by Contoller and Module classes
	* 
	* @uses Util
	* 
	* @Author Mallory Dessaintes <mdessaintes@gmail.com>
	* @version 1.0
	*/
	abstract class ControllerBase extends A\AbstractBase {
		const VIEW_CLASS = 'Aspic\View\View';
		const VIEWS_PATH = 'views';
	
		const INIT_METHOD_NAME = 'init';
		const END_METHOD_NAME = 'end';
		
		/**
		* @var bool True is the action is suspended (the action will not be executed, you must call the suspendAction in the init method of the controller)
		*/
		protected $_isSuspended = false;
		
		protected $_specialParams;
		
		protected $view;
		
		public function __construct($viewData = null) {
			$this->view = new A\StdData(A\UArray::toArray($viewData, true));
		}
		
		/**
		* Init method that is called before every action
		* If suspendAction is called, then init must return a view path that will be load as action method should do
		*/
		protected function init() { }
		
		/**
		* End method that will be loaded at the end of each action (before loading view)
		*/
		protected function end() { }
		
		protected function getParam($name) {
			return A\Util::getIfIsSet($this->_specialParams[$name]);
		}
		
		protected function setParam($name, $value) {
			$this->_specialParams[$name] = $value;
		}
		
		/**
		* If call, it must be in the init method and the action will not be loaded (admin access denied for example)
		* The init method should then return the view path that will be loaded in place of action view path
		*/
		protected function suspendAction() {
			$this->_isSuspended = true;
		}
		
		protected function isSuspended() {
			return $this->_isSuspended;
		}
		
		/**
		* Return the view object that will be given to the view class
		*/
		protected function getViewObject() {
			return $this->view;
		}
		
		protected function getViewInstance() {
			$viewClass = static::VIEW_CLASS;
			$viewInst = new $viewClass;
			
			return $viewInst;
		}
		
		protected function loadTemplate($path, $returnOutput = false) {
			return $this->loadCustomTemplate($path, $this->view, $returnOutput);
		}
		
		/**
		* Load a view from its relative path
		*/
		protected function loadViewRelativePath($viewPath, $returnOutput = false) {
			$fullPath = $this->getViewFullPath($viewPath);

			if(is_file($fullPath)) {
				return $this->loadTemplate($viewPath, $returnOutput);
			}
			else {
				throw new ViewNotFoundException($fullPath);
			}
		}
		
		/**
		 * Same as loadRelCustomTemplate but you have to give a full path to the template
		 * @param type $fullPath
		 * @param type $viewData
		 * @param type $returnOutput 
		 */
		protected function loadCustomTemplate($fullPath, $viewData, $returnOutput = false) {
			$viewInst = $this->getViewInstance();
			
			if($viewInst instanceof A\View\TemplateLoaderInterface) {
				$viewInst->setView(A\UArray::toArray($viewData));
				$viewInst->addTemplatesDir($this->getViewsPath());
				
				ob_start(); // Enable possibility to cache view by registering shutdown function and retrieve buffer content
				
				if($returnOutput) {
					return $viewInst->getLoadedTemplate($path);
				}
				else {
					$viewInst->loadTemplate($fullPath);
				}
			}
			else {
				throw new A\Exception('View class "'.static::VIEW_CLASS.'" musts implements View\TemplateLoaderInterface.');
			}
		}
		
		/**
		* Return the path to the folder containing views files
		*/
		protected function getViewsPath() {
			return A\UString::joinPath($this->getCurrentModulePath(), static::VIEWS_PATH);
		}
		
		abstract protected function getCurrentModulePath();
		
		/**
		* Return the full path of a view file from module path and view filename
		*/
		protected function getViewFullPath($viewFileName) {
			return A\UString::joinPath($this->getViewsPath(), $viewFileName);
		}
		
	}
	
?>